﻿using System;
using Flight.Controller.Entities;
using Flight.Controller.Managers;
using Microsoft.SPOT;

namespace FlightController
{
    /// <summary>
    /// Represents a base flight controller.
    /// </summary>
    public abstract class BaseController
    {
        private Engine[] _engines;

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseController"/> class.
        /// </summary>
        /// <param name="engines">Engines used by this controller.</param>
        /// <param name="manager">Engine manager for speficied engines.</param>
        /// <param name="sensor">Sensors manager to use for flight.</param>
        public BaseController(Engine[] engines, IEngineManager manager, ISensorManager sensor)
        {
            _engines = engines;
            EngineManager = manager;
            SensorManager = sensor;
        }

        /// <summary>
        /// Gets the engines to be controlled.
        /// </summary>
        protected Engine[] Engines
        {
            get
            {
                return _engines;
            }
        }

        /// <summary>
        /// Gets or sets the current altitude in centimeters.
        /// </summary>
        public ushort CurrentAltitude { get; set; }

        /// <summary>
        /// Gets or sets the minimal throttle (0 to 100) to take altitude.
        /// </summary>
        public byte MinLiftThrottle { get; set; }

        /// <summary>
        /// Gets or sets the sensor manager.
        /// </summary>
        protected ISensorManager SensorManager { get; set; }

        /// <summary>
        /// Gets or sets the engine manager.
        /// </summary>
        protected IEngineManager EngineManager { get; set; }

        /// <summary>
        /// Executes yaw move.
        /// </summary>
        /// <param name="degrees">Yaw degrees.</param>
        /// <param name="speed">Move speed.</param>
        public abstract void DoYaw(short degrees, byte speed);

        /// <summary>
        /// Executes pitch move.
        /// </summary>
        /// <param name="degrees">Pitch degrees.</param>
        /// <param name="speed">Move speed.</param>
        public abstract void DoPitch(short degrees, byte speed);

        /// <summary>
        /// Executes roll move.
        /// </summary>
        /// <param name="degrees">Roll degrees.</param>
        /// <param name="speed">Move speed.</param>
        public abstract void DoRoll(short degrees, byte speed);

        /// <summary>
        /// Executes moving to specified altitude.
        /// </summary>
        /// <param name="centimeters">Atitude to set in centimeters.</param>
        public abstract void SetAltitude(ushort centimeters, byte speed);

        /// <summary>
        /// Executes stabilization on all axis. Stops moving and stands free in the air.
        /// </summary>
        public virtual void Stabilize()
        {
            if (MinLiftThrottle == 0)
                throw new InvalidOperationException("Cannot stabilize with min lift set at 0");

            ApplyAllThrottle(MinLiftThrottle);
        }

        /// <summary>
        /// Executes parachute opening.
        /// </summary>
        public virtual void LaunchParachute()
        {
            ApplyAllThrottle(0);

            //Child class must execute proper action.
        }

        /// <summary>
        /// Apply same throttle to all engines.
        /// </summary>
        /// <param name="throttle"></param>
        protected void ApplyAllThrottle(byte throttle)
        {
            foreach (Engine e in Engines)
                EngineManager.SetThrottle(e, throttle);
        }
    }
}
